use std::ops::Deref;
use std::sync::{Arc, Mutex};

use salvo::{Depot, handler, Response};
use salvo::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug)]
pub struct AppState {
    pub books: Mutex<Vec<Book>>,
}
impl AppState {
    pub fn new() -> Self {
        Self {
            books: Mutex::new(Vec::new()),
        }
    }
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Book {
    pub name: String,
}
impl Book {
    pub fn new() -> Self {
        Self {
            name: uuid::Uuid::new_v4().to_string()
        }
    }
}

#[handler]
pub async fn book_list(depot: &mut Depot, res: &mut Response) {
    let state = depot.obtain::<Arc<AppState>>().unwrap();
    let books = &state.books.lock().unwrap();
    res.render(Json(books.deref()));
}
#[handler]
pub async fn book_add(depot: &mut Depot) {
    let state = depot.obtain::<Arc<AppState>>().unwrap();
    let books = &mut state.books.lock().unwrap();
    books.push(Book::new());
}

#[cfg(test)]
mod tests {
    use salvo::oapi::__private::serde_json;
    use salvo::Service;
    use salvo::test::{ResponseExt, TestClient};
    use tokio::test;
    use crate::depot::Book;
    use crate::router;

    #[test]
    async fn test_book_list() {
        let service = Service::new(router());
        let content = TestClient::get(format!("http://127.0.0.1:14300/book"))
            .send(&service).await.take_string().await.unwrap();
        assert_eq!("[]", content);
    }
    #[test]
    async fn test_book_add() {
        let service = Service::new(router());

        let content = TestClient::post(format!("http://127.0.0.1:14300/book/add"))
            .send(&service).await.take_string().await.unwrap();
        assert_eq!("", content);

        let content = TestClient::get(format!("http://127.0.0.1:14300/book"))
            .send(&service).await.take_string().await.unwrap();
        let result = serde_json::from_str::<Vec<Book>>(&content).unwrap();
        assert_eq!(1, result.len());
    }
}